﻿using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;

namespace SearchBoxSample
{
    [TemplatePart(Name="PART_SearchBox",Type=typeof(TextBox))]
    public class SearchBox:Control
    {
        public static readonly DependencyProperty IsOpenProperty;
        public static readonly DependencyProperty SearchTextProperty;

        private CollectionViewSource collectionViewSource;
        private TextBox searchBox;

        public bool IsOpen
        {
            get
            {
                return (bool)base.GetValue(SearchBox.IsOpenProperty);
            }
            private set
            {
                base.SetValue(SearchBox.IsOpenProperty, value);
            }
        }
        public string SearchText
        {
            get
            {
                return (string)base.GetValue(SearchBox.SearchTextProperty);
            }
            set
            {
                base.SetValue(SearchBox.SearchTextProperty, value);
            }
        }

        static SearchBox()
        {
            SearchBox.IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(SearchBox),
                                        new PropertyMetadata(false, new PropertyChangedCallback(SearchBox.OnIsOpenChanged)));
            SearchBox.SearchTextProperty = DependencyProperty.Register("SearchText", typeof(string), typeof(SearchBox), 
                new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(SearchBox.OnSearchTextChanged)));

            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchBox), 
                new FrameworkPropertyMetadata(typeof(SearchBox)));

            Control.IsTabStopProperty.OverrideMetadata(typeof(SearchBox), new FrameworkPropertyMetadata(false));
        }
        public SearchBox()
        {
            IsMouseCaptureWithinChanged += new DependencyPropertyChangedEventHandler(this.OnIsMouseCaptureWithinChanged);
            IsKeyboardFocusWithinChanged += new DependencyPropertyChangedEventHandler(this.OnIsKeyboardFocusWithinChanged);
        }
        #region Static OnMethod
        private static void OnSearchTextChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            ((SearchBox)sender).OnSearchTextChanged(args);
        }
        private static void OnIsOpenChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            ((SearchBox)sender).OnIsOpenChanged(args);
        }
        #endregion

        #region private OnMethod
        private void OnIsMouseCaptureWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (this.IsOpen && !(bool)e.NewValue)
            {
                Mouse.Capture(this, CaptureMode.SubTree);
            }
        }
        private void OnIsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (!(bool)e.NewValue)
            {
                this.IsOpen = false;
            }
        } 
        
        private void OnIsOpenChanged(DependencyPropertyChangedEventArgs args)
        {
            if ((bool)args.NewValue)
            {
                Mouse.Capture(this, CaptureMode.SubTree);
                return;
            }
            Mouse.Capture(null);
            this.SearchText = string.Empty;
        }
        private void OnSearchTextChanged(DependencyPropertyChangedEventArgs args)
        {
            if (this.collectionViewSource != null && this.collectionViewSource.View != null)
            {
                Dispatcher.BeginInvoke(new Action(()=>
                {
                    if (this.collectionViewSource != null)
                    {
                        this.collectionViewSource.View.Refresh();
                        // TODO 
                    }
                }),DispatcherPriority.Background,new object[0]);
            }
        }
        #endregion

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            if (this.searchBox != null)
            {
                this.searchBox.GotFocus -= new RoutedEventHandler(OnSearchBoxGotFocus);
            }
            this.searchBox = GetTemplateChild("PART_SearchBox") as TextBox;
            if (this.searchBox != null)
            {
                this.searchBox.GotFocus += new RoutedEventHandler(OnSearchBoxGotFocus);
            }
        }
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (e.OriginalSource == this && this.IsOpen)
            {
                this.IsOpen = false;
                base.Focus();
                e.Handled = true;
            }
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (this.IsOpen && !e.Handled && e.Key == Key.Escape)
            {
                this.IsOpen = false;
                if (this.searchBox != null)
                {
                    this.searchBox.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
                }
                e.Handled = true;
            }
            base.OnKeyDown(e);
        }
        private void OnSearchBoxGotFocus(object sender, RoutedEventArgs e)
        {
            this.IsOpen = true;
        }
    }
}
